<!--
 * @Author: wei_jt@ecidi.com
 * @Date: 2019-09-17 16:44:32
 * @LastEditors: chen_yt
 * @LastEditTime: 2022-08-17 16:30:10
 * @Description: 菜单配置
 -->
<template>
  <div class="main-wrapper drawer-container">
    <div v-if="multiPortal" class="left-container">
      <div class="resize-bar-vertical" />
      <div class="resize-line-vertical" />
      <div class="left-top-content">
        <portalSelect :show-search="true" @refresh="refreshData" />
      </div>
    </div>
    <div class="right" :style="{ flexGrow: 1 }">
      <div class="line-button">
        <div class="page-button">
          <div class="page-title" style="display: flex">
            <div class="fks-title-icon" />
            <span class="table-title">{{ LANG.MENU_MANAGEMENT }}</span>
          </div>
          <div>
            <fks-input
              v-model="keywords"
              size
              style="width: auto; margin-left: 8px"
              :placeholder="LANG.INPUT_ROUTENAME_OR_ROUTEPATH"
              clearable
              maxlength="50"
              @keyup.native.enter="getMenuTree"
              @clear="getMenuTree"
            >
              <fks-button
                slot="append"
                icon="fks-icon-search"
                @click="getMenuTree"
              />
            </fks-input>
            <fks-button style="margin-left: 8px" @click="show = !show">
              <fks-checkbox
                v-model="show"
                style="font-size: 0; vertical-align: bottom"
                @click.native.stop
              />
              <span style="margin-left: 8px">{{ LANG.NOT_HIDDEN }}</span>
            </fks-button>
            <fks-button
              v-permission="['menu:import']"
              style="margin-left: 8px"
              @click="importData"
            >
              <i class="fks-icon-import" />
              <span style="margin-left: 8px">{{ LANG.IMPORT }}</span>
            </fks-button>
            <fks-button
              v-permission="['menu:export']"
              style="margin-left: 8px"
              @click="exportData"
            >
              <i class="fks-icon-export" />
              <span style="margin-left: 8px">{{ LANG.EXPORT }}</span>
            </fks-button>
            <fks-button
              v-permission="['menu:add']"
              type="primary"
              style="margin-left: 8px"
              icon="fks-icon-plus"
              @click="addRootNode"
            >
              {{ LANG.ADD }}
            </fks-button>
          </div>
        </div>
      </div>
      <fks-table
        ref="tree"
        v-loading="loading"
        class="menu-table"
        :data="treeData"
        row-key="id"
        height="calc(100% - 65px)"
        @row-click="rowClick"
        @select="handleSelection"
        @selection-change="handleSelectionChange"
        @select-all="handleSeletionAll"
      >
        <fks-table-column type="selection" width="55" />
        <fks-table-column
          :label="LANG.NAME"
          prop="title"
          header-align="center"
          min-width="200px"
          align="left"
        >
          <template slot-scope="scope">
            {{ LANG[scope.row.content.title] || scope.row.content.title }}
          </template>
        </fks-table-column>
        <fks-table-column
          :label="LANG.ROUTEPATH"
          prop="content.path"
          min-width="300px"
          header-align="center"
          align="left"
        />
        <fks-table-column
          prop="enable"
          align="center"
          header-align="center"
          min-width="100"
        >
          <template slot="header">
            {{ LANG.ACTIVATE }}
          </template>
          <template slot-scope="scope">
            <div @click.stop.prevent>
              <fks-switch
                v-model="scope.row.content.enable"
                :active-value="true"
                :inactive-value="false"
                :disabled="
                  !(activePermission && canEditCommonMenu(scope.row.content))
                "
                @change="change(scope.row)"
              />
            </div>
          </template>
        </fks-table-column>
        <fks-table-column :label="LANG.IS_AUTH" prop="auth" align="center">
          <template slot-scope="scope">
            <div @click.stop.prevent>
              <fks-switch
                v-model="scope.row.content.isAuth"
                :active-value="true"
                :inactive-value="false"
                :disabled="
                  !(authPermission && canEditCommonMenu(scope.row.content))
                "
                @change="change(scope.row)"
              />
            </div>
          </template>
        </fks-table-column>
        <fks-table-column
          :label="LANG.SORT"
          prop="content.sort"
          align="center"
          width="100"
        />
        <fks-table-column
          v-if="multiPortal"
          :label="LANG.IS_GENERAL"
          min-width="150"
          align="center"
        >
          <template slot-scope="scope">
            {{ scope.row.content.isGeneral ? LANG.YES : LANG.NO }}
          </template>
        </fks-table-column>
        <fks-table-column :label="LANG.OPERATION" width="200" align="left">
          <template slot-scope="scope">
            <fks-tooltip
              class="item"
              :content="LANG.DELETE_TIP"
              placement="top"
              :disabled="canEditCommonMenu(scope.row.content)"
            >
              <span style="margin-right: 10px">
                <fks-button
                  v-permission="['menu:edit']"
                  :disabled="!canEditCommonMenu(scope.row.content)"
                  type="text"
                  @click.stop="edit(scope.row.content)"
                >
                  {{ LANG.EDIT }}
                </fks-button>
              </span>
            </fks-tooltip>
            <fks-button
              v-permission="['menu:add']"
              type="text"
              @click.stop="addSubMenu(scope.row.content)"
            >
              {{ LANG.ADD_CHILD }}
            </fks-button>
            <fks-tooltip
              class="item"
              :content="LANG.DELETE_TIP"
              placement="top"
              :disabled="canEditCommonMenu(scope.row.content)"
            >
              <span style="margin-left: 10px">
                <fks-button
                  v-permission="['menu:delete']"
                  :disabled="!canEditCommonMenu(scope.row.content)"
                  danger-text
                  @click.stop="handleDelete(scope.row.content.id)"
                >
                  {{ LANG.DELETE }}
                </fks-button>
              </span>
            </fks-tooltip>
          </template>
        </fks-table-column>
      </fks-table>
    </div>
    <menuImportErrorTip
      v-if="menuImportErrorVisible"
      :visible.sync="menuImportErrorVisible"
      :menu-error-data="menuErrorData"
      :menu-error-flag="menuErrorFlag"
    />
    <menu-detail
      v-if="visible"
      :data="node"
      :visible.sync="visible"
      @reset="reset"
    />
    <div v-if="exportVisible">
      <menu-import-exoprt
        :type="operateType"
        :export-menu-list="exportMenuData"
        :portal="authPortal"
        :visible.sync="exportVisible"
        :menu-tree-data="treeData"
        @fetchData="getMenuTree"
        @showErrorTip="showErrorTips"
      />
    </div>
  </div>
</template>
<script>
import * as Auth from "./api";
import MenuDetail from "./MenuDetail";
import menuImportExoprt from "./components/MenuImportExport";
import Mix from "@/mixins/module";
import portalSelect from "@/components/PortalSelect";
import menuImportErrorTip from "./components/MenuImportErrorTip";
import { arrayToTree } from "@/utils/array";
import { ENUM, PORTALS } from "@/store/State/stateTypes";
import { AUTH_PORTAL } from "@/store/Getter/getterTypes.js";
export default {
  name: "Menu",
  components: {
    MenuDetail,
    menuImportExoprt,
    menuImportErrorTip,
    portalSelect,
  },
  filters: {
    /**
     * @description: 超过多少字省略
     * @param {type}
     * @return:
     */
    ellipsis(value, node) {
      let num = 16 - (node.level - 1) * 2;
      if (node.isLeaf) {
        num++;
      }
      if (value && value.length > num) {
        return value.substring(0, num - 2) + "...";
      } else {
        return value;
      }
    },
  },
  mixins: [Mix],
  data() {
    return {
      searchValue: "",
      operateType: "import",
      menuImportErrorVisible: false,
      defaultProps: {
        children: "children",
        label: "name",
      },
      chosedPotal: [],
      keywords: "",
      node: {},
      visible: false,
      showNode: true,
      loading: false,
      treeList: [],
      show: true,
      auth: "",
      ACESS_TOKEN: this.$storage.get("access_token"),
      uploadUrl: "",
      operate: "",
      exportVisible: false,
      exportMenuData: [],
      fileList: [],
      potalTree: [],
      currentEditPotal: {},
      selectedIndex: 1,
      menuErrorData: [],
      menuErrorFlag: false,
    };
  },
  computed: {
    multiPortal() {
      return this.$store.getters.multiPortal;
    },
    title() {
      switch (this.operate) {
        case "export":
          return this.LANG.EXPORT_CONFIG;
        default:
          return this.LANG.IMPORT_CONFIG;
      }
    },
    treeData() {
      let origin = JSON.parse(JSON.stringify(this.treeList));
      return this.filterTable(origin, this.keywords) || [];
    },
    activePermission() {
      return this.nodePermission(["menu:activate", "menu:edit"]);
    },
    authPermission() {
      return this.nodePermission(["menu:auth", "menu:edit"]);
    },
    portalTypes() {
      return this.$store.state[ENUM].portalType || [];
    },
    portals() {
      return this.$store.state[PORTALS];
    },
    portalList() {
      let portalList = [];
      this.portalTypes.forEach((e) => {
        let arr = this.portals.filter((p) => {
          return p.type == e.code;
        });
        if (arr && arr.length) {
          let portal = Object.assign({ list: arr }, e);
          portalList.push(portal);
        }
      });
      return this.filterPortal(portalList, this.searchValue) || [];
    },
    authPortal() {
      return this.$store.getters[AUTH_PORTAL] || {};
    },
  },
  beforeDestroy() {
    this.treeList = [];
  },
  mounted() {
    this.getMenuTree();
  },
  methods: {
    refreshData() {
      this.exportMenuData = [];
      this.getMenuTree();
    },
    showErrorTips(responseData, menuErrorFlag) {
      this.menuImportErrorVisible = true;
      this.menuErrorFlag = menuErrorFlag;
      this.menuErrorData = responseData;
    },
    canEditCommonMenu(content) {
      if (!this.multiPortal) {
        return true;
      }
      if (this.authPortal.portalId && content.isGeneral) {
        return false;
      }
      return true;
    },
    /**
     * @description: 编辑按钮弹窗关闭时，恢复树的可收缩伸展
     * @param {Boolean}
     * @return:
     */
    reset(params) {
      this.showNode = params;
    },
    /**
     * @description: 获取菜单树
     * @param {type}
     * @return:
     */
    @permission("menu:query")
    getMenuTree() {
      this.visible = false;
      this.loading = true;
      return new Promise((resolve) => {
        // let params = this.authPortal
        Auth.getMenusTree(this.authPortal)
          .then((res) => {
            if (res.status) {
              this.treeList = [...res.data];
            } else {
              this.treeList = [];
            }
            this.loading = false;
            resolve(true);
          })
          .catch(() => {
            this.treeList = [];
            this.loading = false;
            resolve(true);
          });
      });
    },
    //点击表格回调
    rowClick(row) {
      if (!row.children) {
        if (this.$refs.tree.selection.includes(row)) {
          this.$refs.tree.toggleRowSelection(row, false);
        } else {
          this.$refs.tree.toggleRowSelection(row, true);
        }
        return;
      }
      if (this.$refs.tree.selection.includes(row)) {
        this.$refs.tree.toggleRowSelection(row, false);
        this.checkRow(row.children, false);
      } else {
        this.$refs.tree.toggleRowSelection(row, true);
        this.checkRow(row.children, true);
      }
    },
    edit(data) {
      //点击编辑时 树不收缩伸展
      this.showNode = false;
      this.node = Object.assign({}, data);
      this.node.operate = "edit";
      this.visible = true;
    },

    /**
     * @description: 删除菜单
     * @param {id}
     * @return:
     */
    handleDelete(id) {
      this.$confirm(this.LANG.CONFIRM_TIPS, this.LANG.TIPS, {
        type: "warning",
        confirmButtonText: this.LANG.DELETE,
        cancelButtonText: this.LANG.CANCEL,
        confirmButtonClass: "fks-button--danger",
        deleteMode: true,
      })
        .then(() => {
          Auth.deleteMenu(id)
            .then((res) => {
              if (res.status) {
                this.$message.success(this.LANG.DELETE_SUCCESS);
                this.getMenuTree();
              }
            })
            .catch(() => {});
        })
        .catch(() => {});
    },

    /**
     * @description: 新增子菜单节点-打开弹窗
     * @param {val}
     * @return:
     */
    addSubMenu(val) {
      this.node = { pathId: val.pathId, parentId: val.id, operate: "add" };
      this.visible = true;
    },
    /**
     * @description: 新增根菜单节点-打开弹窗
     * @param {}
     * @return:
     */
    addRootNode() {
      this.node = { parentId: "", operate: "add", icon: "" };
      this.visible = true;
    },
    //选中菜单
    handleSelection(select, row) {
      if (!row.children) {
        return false;
      }
      if (this.$refs.tree.selection.includes(row)) {
        this.checkRow(row.children, true);
      } else {
        this.checkRow(row.children, false);
      }
    },
    //选择改变
    handleSelectionChange() {
      let data = [];
      this.$refs.tree.selection.forEach((item) => {
        let val = {};
        val = item.content;
        if (item.children) {
          val.children = item.children;
        }
        data.push(val);
      });
      let treeData = arrayToTree(data, "parentId", "0", true);
      this.exportMenuData = treeData;
    },

    //全选
    handleSeletionAll(select) {
      if (this.$refs.tree.$refs.tableHeader.isAllSelected) {
        this.checkRow(select, true);
      } else {
        this.$refs.tree.clearSelection();
      }
    },

    //选中递归
    checkRow(data, bool) {
      data.forEach((item) => {
        this.$refs.tree.toggleRowSelection(item, bool);
        if (item.children) {
          this.checkRow(item.children, bool);
        }
      });
    },
    filterPortal(list, val) {
      if (!val) return list;
      return list.filter((item) => {
        // debugger
        if (item.list) {
          let arr = this.filterPortal(item.list, val);
          item.list = arr;
          if (arr instanceof Array && arr.length > 0) {
            return true;
          }
        }
        if (item.name && item.name.indexOf(val) != -1) {
          return true;
        }
        if (item[this.$lang] && item[this.$lang].indexOf(val) != -1) {
          return true;
        }
        return false;
      });
    },
    //过滤树形数据
    filterTable(list, val) {
      return list.filter((item) => {
        if (!this.show && !item.content.enable) {
          return false;
        }
        if (item.children) {
          let arr = this.filterTable(item.children, val);
          item.children = arr;
          if (arr instanceof Array && arr.length > 0) {
            return true;
          }
        }

        if (!item.content.title) {
          return false;
        }

        if (
          this.LANG[item.content.title] &&
          this.LANG[item.content.title].indexOf(val) != -1
        ) {
          return true;
        }

        if (item.content.title.indexOf(val) != -1) {
          //满足未配置多语言的情况
          return true;
        }
        return false;
      });
    },

    /**
     * @description: 列表中编辑菜单
     * @param {val}
     * @return:
     */
    change(row) {
      Auth.saveMenu(row.content)
        .then((res) => {
          if (res.status) {
            this.getMenuTree();
            this.$message({
              message: this.LANG.UPDATE_SUCCESS,
              type: "success",
              duration: 3000,
            });
          }
        })
        .catch(() => {});
    },

    //导出
    exportData() {
      if (!this.exportMenuData || !this.exportMenuData.length) {
        this.$message({
          message: this.LANG.EXPORT_TIPS,
          type: "warning",
        });
        return false;
      }
      this.operateType = "export";
      this.exportVisible = true;
    },
    //打开导入菜单弹窗
    importData() {
      let arr = this.$refs.tree?.selection ?? [];
      if (arr.length > 1) {
        this.$message.error(this.LANG.CONFIRM_MENU_ERROR);
      } else {
        this.operateType = "import";
        this.exportVisible = true;
      }
    },
  },
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@import "@/assets/css/variables.scss";
.drawer-container {
  display: flex;
  height: 100%;
  overflow: hidden;
  .left-container {
    position: relative;
    height: 100%;
    .search-input {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
    }
    .resize-bar-vertical {
      z-index: -100 !important;
      width: 300px;
      min-width: 300px; /* 最小宽度 300px */
      max-width: 600px; /* 最大宽度 600px */
      height: inherit;
      overflow: scroll;
      resize: horizontal;
      opacity: 0;
      cursor: col-resize;
    }
    .resize-line-vertical {
      position: absolute;
      top: 0;
      bottom: 0;
      right: 5px;
      height: 100vh;
      border-left: 1px solid #eee;
      pointer-events: none;
    }
    .resize-bar-vertical:hover ~ .resize-line-vertical,
    .resize-bar-vertical:active ~ .resize-line-vertical {
      border-left: 1px solid #eee;
    }
    .resize-bar-vertical::-webkit-scrollbar {
      height: 100vh;
    }
    .left-top-content {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 5px;
      display: flex;
      flex-direction: column;
      height: 100%;
      padding: 24px;
      overflow: hidden;
      ::-webkit-scrollbar {
        width: 0;
      }
    }
  }

  .right {
    box-sizing: border-box;
    width: 100%;
    min-width: 700px;
    height: 100%;
    padding: 24px 32px 24px 24px;
    overflow-y: auto;
    .page-button {
      display: flex;
      justify-content: space-between;
      .table-title {
        font-weight: bold;
        font-size: 16px;
        color: #191919;
      }
    }
  }
}

.line-button {
  margin-bottom: 24px;
}

.menu-upload {
  width: auto;
}
</style>
